package demo1;

//现实中有许多事物有着共同的特性
//比如狗和猫，它们都有名字，年龄，都有吃、睡、跑、叫等共性。这是动物共有的特性。
//那么我们希望可以将这些共性提取出来，定义一个动物类，让狗类和猫类继承它，这样狗类和猫类就拥有了动物类的所有特性。

//继承就是在保持原有类特性的基础上进行扩展，增加新功能，这样产生新的类，称派生类。
//继承呈现了面向对象程序设计的层次结构，体现了由简单到复杂的认知过程。
// 继承主要解决的问题是：共性的抽取，实现代码复用。

class Animal {
    String name;
    int age;
    public void eat() {
        System.out.println("Animal eat");
    }
    public void sleep() {
        System.out.println("Animal sleep");
    }
}

class Dog extends Animal {
    public void bark() {
        System.out.println("Dog 汪汪汪!");
    }
}

class Cat extends Animal {
    public void mew() {
        System.out.println("Cat 喵喵喵!");
    }
}
//狗和猫继承了Animal类，Animal派生出了dog和cat类。

//父类成员的访问
//1. 子类访问父类成员
//  (1)若子类与父类没有同名成员变量，则可以直接通过成员变量名访问
//  (2)若子类与父类有同名成员变量，通过成员变量名访问优先访问子类自己的
//      子类要访问父类同名成员变量，需要使用super关键字
//  总结：如果访问的成员变量子类中有，优先访问自己的成员变量。
//       如果访问的成员变量子类中无，则访问父类继承下来的，如果父类也没有定义，则编译报错。
//       如果访问的成员变量与父类中成员变量同名，则优先访问自己的。
//
//2. 子类访问父类成员方法
//  (1)成员方法无同名时，优先访问的子类的，若子类没有则在父类中找，若父类也没有，则编译报错。
//  (2)成员方法有同名时，若子类与父类的成员方法构成重载，则根据传递的参数决定调用子类的还是父类的
//      若没有(方法重载)，则编译报错。想访问父类的，需要使用super.方法名


//super关键字
//主要作用是在子类中访问父类成员
//例：
class Base {
    int a;
    int b;
    public void methodA() {
        System.out.println("Base里的methodA()");
    }
    public void methodB () {
        System.out.println("Base里的methodB()");
    }
}
class Derived extends Base {
    int a;
    char b;
    int c;
    //与父类的methodA()方法构成了重载
    public void methodA(int a) {
        System.out.println("Derived里的methodA()");
    }
    //与父类的methodB()方法构成重写
    public void methodB () {
        System.out.println("Derived里的methodB()");
    }
    public void methodC() {
        a = 110;
        b = 'x';
        c = 999;
        //同名情况下，直接用成员变量名访问的都是子类自己的
        //注意！！！这里如果使用this，子类和父类的都能访问，但同名时，还是现在子类找，没有就去父类找，找不到报错。
        super.a = 521;
        super.b = 666;
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
        System.out.println(super.a);
        System.out.println(super.b);

        //同名时，访问父类的要用super
        methodA();
        methodA(1);
        //父类与子类构成方法重载时，可以通过参数列表区分，不用super
        methodB();
        super.methodB();
        //父类与子类构成方法重写时，直接通过成员变量名访问只能调用子类的
        //要想调用父类的，必须使用super.方法名
    }
}



//子类构造方法
//先有父再有子：子类对象构造时，需要先调用父类构造方法，然后执行子类的构造方法。
//在子类构造方法中，并没有写任何关于基类构造的代码，但是在构造子类对象时，先执行基类的构造方法，然后执行子类的构造方法

//1. 若父类显式定义无参或者默认的构造方法，在子类构造方法第一行默认有隐含的super()调用，即调用基类构造方法，
//   如上面的Base和Derived类，子类有一个隐含的构造方法，在它的第一行隐含有super()调用，即调用父类构造方法。
//2. 如果父类构造方法是带有参数的，此时需要用户为子类显式定义构造方法，并在子类构造方法中选择合适的父类构造方法调用，否则编译失败。
//3. 在子类构造方法中，super(...)调用父类构造时，必须是子类构造函数中第一条语句。
//4. super(...)只能在子类构造方法中出现一次，并且不能和this同时出现。
//例：
class Student {
    String name;
    int age;
    String classroom;
    public Student(String name, int age, String classroom) {
        this.name = name;
        this.age = age;
        this.classroom = classroom;
    }
}

class Students extends Student {
    public Students(String name, int age, String classroom) {
        super(name, age, classroom);
        System.out.println("Student父类构造已完成");
    }
    public void print() {
        System.out.println("姓名：" + this.name);
        System.out.println("年龄：" + this.age);
        System.out.println("教室：" + this.classroom);
    }
}



//super和this的比较
//相同点：
//1. super和this都是关键字，用于访问成员变量和方法。
//2. super和this只在非静态类中使用，访问非静态类的成员变量和方法。
//3. 在构造方法中调用时，必须是第一条语句，且不能同时存在
//不同点：
//1. this时当前对象的引用，当前对象即调用构造方法的对象，而super是子类对象从父类继承下来的部分成员的引用
//2. 在非静态类里，this用来访问本类的方法和属性，super用来访问父类的方法和属性
//3. 在构造方法中：this(...)用于调用本类构造方法，super(...)用于调用父类构造方法，两种调用不能同时在构造方法中出现
//4. 构造方法中一定会存在super(...)的调用，用户没有写编译器也会增加，但是this(...)用户不写则没有



//代码块的执行顺序：
//父类的静态代码块 -> 子类的静态代码块 -> 父类的实例代码块 -> 父类的构造方法 -> 子类的实例代码块 -> 子类的构造方法